home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 1 (Walnut Creek)
/
Aminet - June 1993 [Walnut Creek].iso
/
usenet
/
sources
/
volume2
/
util
/
suplib.dcs
< prev
next >
Wrap
Internet Message Format
|
1988-10-22
|
26KB
Path: xanth!nic.MR.NET!hal!cwjcc!mailrus!uflorida!gatech!bbn!ulowell!page
From: page@swan.ulowell.edu (Bob Page)
Newsgroups: comp.sources.amiga
Subject: v02i007: suplib-docs - documentation for Matt's support library
Message-ID: <9769@swan.ulowell.edu>
Date: 22 Oct 88 04:16:24 GMT
Organization: University of Lowell, Computer Science Dept.
Lines: 781
Approved: page@swan.ulowell.edu
Submitted-by: dillon@cory.berkeley.edu (Matt Dillon)
Posting-number: Volume 2, Issue 7
Archive-name: util/suplib.docs
[Matt sent 2 DISKS full of stuff ... my first week on the job! :-) ..Bob]
# This is a shell archive. Remove anything before this line
# then unpack it by saving it in a file and typing "sh file"
# (Files unpacked will be owned by you and have default permissions).
# This archive contains the following files:
# ./dio.doc
# ./qint.doc
# ./summary.doc
# ./suplib.doc
#
if `test ! -s ./dio.doc`
then
echo "writing ./dio.doc"
cat > ./dio.doc << '\Rogue\Monster\'
DIO
EXEC device driver IO support routines... makes everything easy.
dfd = dio_open(name, unit, flags, req/NULL)
open an IO device. Note: in some cases you might have to provide a
request structure with some fields initialized (example, the console
device requires certain fields to be initialized). For instance, if
openning the SERIAL.DEVICE, you would want to give an IOExtSer
structure which is completely blank execept for the io_SerFlags
field.
The request structure's message and reply ports need not be
initialized. The request structure is no longer needed after
the dio_open().
returns NULL = error, else DIO descriptor (a pointer) returned.
dio_close(dfd)
close an IO device. Any pending asyncronous requests are
AbortIO()'d and then Wait'ed on for completion.
dio_closegrp(dfd)
close EVERY DIO DESCRIPTOR ASSOCIATED WITH THE dio_open() call
that was the parent for this descriptor. That is, you can get
a descriptor using dio_open(), dio_dup() it a couple of times,
then use dio_closegrp() on any ONE of the resulting descriptors
to close ALL of them.
dio_cact(dfd,bool)
If an error occurs (io_Error field), the io_Actual field is usually
not modified by the device driver, and thus contains garbage. To
provide a cleaner interface, you can have the DIO_CTL() and
DIO_CTL_TO() calls automatically pre-clear this field so if an
io_Error does occur, the field is a definate 0 instead of garbage.
In most cases you will want to do this. An exception is the
TIMER.DEVICE, which uses the io_Actual field for part of the timeout
structure.
This flags the particular dio descriptor to do the pre-clear, and any
new descriptors obtained by DIO_DUP()ing this one will also have the
pre-clear flag set.
dio_dup(dfd)
Returns a new channel descriptor referencing the same device. The new
descriptor has it's own signal and IO request structure. For
instance, if you openned the serial device, you might want to dup the
descriptor so you can use one channel to pend an asyncronous read,
and the other channel to write out to the device and do other things
without disturbing the asyncronous read.
sig = dio_signal(dfd)
get the signal number (0..31) used for a DIO descriptor. This allows
you to Wait() for asyncronous requests. Note that if your Wait()
returns, you should double check using dio_isdone()
req = dio_ctl_to(dfd, command, buf, len, to)
Same as DIO_CTL() below, but (A) is always syncronous, and (B) will
attempt to AbortIO()+WaitIO() the request if the timeout occurs
before the IO completes.
the 'to' argument is in microseconds.
If timeout occurs before request completes, and DIO aborts the
request, some devices, such as the SERIAL.DEVICE do not have the
io_Actual field set properly. Always check the io_Error field for
an abort before using io_Actual.
req = dio_ctl(dfd, command, buf, len)
DIO_CTL() is the basis for the entire library. It works as follows:
(1) If the channel isn't clear (there is an asyncronous IO request
still pending), DIO_CTL() waits for it to complete
(2) If the command is 0, simply return a pointer to the io
request structure.
(3) If the DIO_CACT() flag is TRUE, the io_Actual field of the
request is cleared.
(4) Set the io_Data field to 'buf', and io_Length field to 'len'
If the command is positive, use DoIO(). If the command
negative, take it's absolute value and then do a SendIO().
(The command is placed in the io_Command field, of course).
(5) return the IO request structure
bool= dio_isdone(dfd)
return 1 if current channel is clear (done processing), else 0. e.g.
if you did, say, an asyncronous read, and dio_isdone() returns true,
you can now use the data buffer returned and look at the io_Actual
field.
You need not do a dio_wait() after dio_isdone() returns 1.
req = dio_wait(dfd)
Wait on the current channel for the request to complete and then
return the request structure. (nop if channel is clear)
req = dio_abort(dfd)
Abort the request on the current channel (nop if channel is
clear). Sends an AbortIO() if the channel is active and then
WaitIO()'s the request.
------ MACROS ------
dio_simple() and related macros return the !io_Error field. That
is, 0=ERROR, 1=OK
dio_actual() returns the io_Actual field instead of !io_Error.
NOTE: the io_Actual field may not be set by the device if an
error condition exists. To make the io_ctl() and io_ctl_to()
call automatically clear the io_Actual field before doing the
io operation, use the DIO_CACT() call. The reason this isn't
done automatically by default is that some devices require
parameters to be passed in the io_Actual field (like the
timer.device).
Remember, Asyncronous IO is done by sending -com instead of com.
(that is, negative command).
CALL Syncronous IO Asyncronous IO
dio_simple(dfd,com) 0=ERROR, 1=OK undefined
dio_actual(dfd,com) io_Actual undefined
dio_reset(dfd) 0=ERROR, 1=OK n/a
dio_update(dfd) 0=ERROR, 1=OK n/a
dio_clear(dfd) 0=ERROR, 1=OK n/a
dio_stop(dfd) 0=ERROR, 1=OK n/a
dio_start(dfd) 0=ERROR, 1=OK n/a
dio_flush(dfd) 0=ERROR, 1=OK n/a
dio_getreq(dfd) returns a ptr to the IO
request structure
NOTE: If you use the following, you probably want to have the device
library automatically clear the io_Actual field before sending the
request so you get 0 if an error occurs. That is: dio_cact(dfd,1):
dio_read(dfd,buf,len) returns actual bytes read
dio_write(dfd,buf,len) returns actual bytes written
The timeout argument for dio_readto() and dio_writeto()
is in MICROSECONDS, up to 2^31uS.
dio_readto(dfd,buf,len,to) returns actual bytes read
dio_writeto(dfd,buf,len,to) returns actual bytes written
The asyncronous dio_reada() and dio_writea() do not
return anything.
dio_reada(dfd,buf,len) begin asyncronous read
dio_writea(dfd,buf,len) begin asyncronous write
\Rogue\Monster\
else
echo "will not over write ./dio.doc"
fi
if [ `wc -c ./dio.doc | awk '{printf $1}'` -ne 6534 ]
then
echo `wc -c ./dio.doc | awk '{print "Got " $1 ", Expected " 6534}'`
fi
if `test ! -s ./qint.doc`
then
echo "writing ./qint.doc"
cat > ./qint.doc << '\Rogue\Monster\'
QINT DOCUMENTATION
Matthew Dillon
dillon@ucbvax.berkeley.edu ARPA
...!ihnp4!ucbvax!dillon USENET
NOTE!!!!! Lattice Users must replace the 'jsr _geta4' call with the
appropriate call to retrieve the address register for the
small data model before compiling! You might have to make
other modifications as well (I don't know since I don't
have Lattice).
The Calls:
char oldpri; range -128 to 127
char newpri;
char pri;
long signum; 0 .. 31
void (*vector)(); function vector returning nothing
void (*oldvec)();
While active Q interrupt vectors exist, the tc_ExceptCode in the
task structure will be modified. The old tc_ExceptCode is used if
an unknown exception occurs (one that is not a Q interrupt).
oldpri = SetQPri(newpri)
Set the task's current Q priority. Any Q interrupts of lower or
equal priority that occur will be queued until the priority is
dropped sufficiently.
The initial task priority is -128 (essentially allowing all Q
interrupts -127 to 127 to occur).
oldvec = SetQVector(signum, vector, arg, pri)
If vector is non-null, enables the exception at the specified
priority (-127 to 127). specified vector is called in a C
compatible way with one user argument (arg). Specifying a
priority of -128 does not make sense because this is the lowest
allowed priority and the Q interrupt will thus never occur.
If vector is null, the exception and Q interrupt is disabled.
After the last Q interrupt is removed, tc_ExceptCode is restored
to its original value.
BUGS:
The only bug that I know of is a problem with EXEC.
What is Good: An exception will not occur while one is Forbid()n
What is Bad: If an exception comes in while Forbid()n, it will
NOT be immediately entered when you Permit().
Whoops. The exception *will* occur when EXEC next checks its
signals and exceptions, which occurs on the obvious EXEC library
calls (SetExcept(), SetSignal(), etc...) and perhaps Wait().
In most cases you can ignore the problem.
GENERAL WORKINGS OF Q INTERRUPTS:
If you know how EXEC signals and the 68000 interrupt structure
works, then you know how Q interrupts work. Simply replace
"processor" with "task" and "0-7" with "-128 to 127" for task
Q interrupt priorities (this is different from the Task's
scheduler priority).
Q interrupts work just like 68000 interrupts. If the task is
currently running at a Q interrupt priority N, only Q interrupts
of HIGHER priority can occur. Q interrupts of LOWER OR EQUAL
priority are queued and will occur as soon as the priority is
lowered. Everything occurs in priority order, the highest priority
pending interrupt is always the one running (or the task's main
routine if it has the highest priority).
Thus, while a Q interrupt handler is running at some specific
priority, other Q interrupts at the same priority will wait
until the first one finishes and then execute in a FIFO fashion.
THE INTERRUPT VECTOR ROUTINE:
A specific Q interrupt vector is a C subroutine called with one
longword argument (that specified when you SetQVector()'d it).
This works fine with the small model.
The handler runs with all normal EXEC processing enabled, and in
the context of its task. It can be viewed almost as a subroutine
call from the task. However, you must be careful about the
reentrancy of certain functions. STDIO, DOS, and many other
library calls are not reentrant, and you must use SetQPri() to
ensure such calls are not interrupted. NOTE that you CAN mix
certain calls. I don't have much info on what combinations work,
but certainly most library calls that do not depend on being
called singularly from tasks will work (for example, GetMsg()).
And, of course, if all your handler does is make some small
calculations this can interrupt anything.
If you cause an exception (the same exception) from within the
handler, it will be remembered. (That is, the signal is cleared
before the handler is called), and occur after your handler
returns.
USES FOR Q INTERRUPTS:
Use #1: To be able to execute menu options which do not effect
the 'current' operation. E.G. if you are doing a
ray tracing you could make the intuition window's
signal bit a Q interrupt and handle Intuition messages
that way.... The main loop generating the ray
tracing would not have to continuously check for
Intuition messages.
Use #2: Lets say you are writing a terminal program and want
to display data comming in smoothly while sending a
file. While this can be done easily with the
asynchronous ability of IO devices, it would be even
easier if you handled the receive with a Q interrupt...
that way, you could display received data (SendIO to
the console device) even if the file sender is in
the middle of a DOS call to read the next file block.
Many more uses (I hope!).
-Matt
\Rogue\Monster\
else
echo "will not over write ./qint.doc"
fi
if [ `wc -c ./qint.doc | awk '{printf $1}'` -ne 4986 ]
then
echo `wc -c ./qint.doc | awk '{print "Got " $1 ", Expected " 4986}'`
fi
if `test ! -s ./summary.doc`
then
echo "writing ./summary.doc"
cat > ./summary.doc << '\Rogue\Monster\'
SUMMARY.DOC Summary of library functions
-------- ASYNCHRONOUS FILE SUPPORT --------
xfi = xfopen(file, mode, bytes) mode: r-read w-write w+-append
err = xfclose(xfi)
n = xfread(xfi, buf, n) 0 on EOF/error
n = xfgets(xfi, buf, max) -1 on EOF/error else string length
err = xfwrite(xfi, buf, n)
bmov(src,dest,bytes)
bcmp(src,dest,bytes)
bset(src, bytes, c)
bzero(src, bytes)
checkbreak()
resetbreak()
disablebreak() (not available as a run-time library call)
enablebreak() (not available as a run-time library call)
openlibs(flags)
closelibs(flags)
closelibs(-1) close all libraries openned w/ openlibs()
bool = wildcmp(wildstr, namestr)
mountrequest(bool)
fhprintf(fh, ctrlstr, args...)
llink(list, en) (OBSOLETE)
lunlink(en) (OBSOLETE)
SYSTEM SUPPORT
port = CreateUniquePort(name, priority) create port w/unique name
DeleteUniquePort(port) delete port w/unique name
PutSyncMsg(port, msg) normal synchronous message
PutSyncMsgSimple(port, ptr, cmd) simple synchronous message
retcmd = WaitMsg(msg) wait for message to come back
CheckMsg(msg) check if message has come back
GetHead(list)
GetTail(list)
NextNode(node)
IO SUPPORT
dfd = dio_open(name, unit, flags, req/NULL)
dio_close(dfd)
dio_closegrp(dfd)
dio_cact(dfd,bool)
dio_dup(dfd)
sig = dio_signal(dfd)
req = dio_ctl_to(dfd, command, buf, len, to)
req = dio_ctl(dfd, command, buf, len)
bool= dio_isdone(dfd)
req = dio_wait(dfd)
req = dio_abort(dfd)
also a large array of macros are available. if command < 0, then
asyncronous execution is implied. Macros:
SYCHRONOUS ASYNCHRONOUS
dio_simple(dfd,com) 0=ERROR, 1=OK undefined
dio_actual(dfd,com) io_Actual undefined
dio_reset(dfd) 0=ERROR, 1=OK n/a
dio_update(dfd) 0=ERROR, 1=OK n/a
dio_clear(dfd) 0=ERROR, 1=OK n/a
dio_stop(dfd) 0=ERROR, 1=OK n/a
dio_start(dfd) 0=ERROR, 1=OK n/a
dio_flush(dfd) 0=ERROR, 1=OK n/a
dio_getreq(dfd) returns a ptr to the IO request structure
dio_read(dfd,buf,len) returns actual bytes read
dio_write(dfd,buf,len) returns actual bytes written
dio_readto(dfd,buf,len,to) returns actual bytes read
dio_writeto(dfd,buf,len,to) returns actual bytes written
dio_reada(dfd,buf,len) begin asyncronous read
dio_writea(dfd,buf,len) begin asyncronous write
\Rogue\Monster\
else
echo "will not over write ./summary.doc"
fi
if [ `wc -c ./summary.doc | awk '{printf $1}'` -ne 2888 ]
then
echo `wc -c ./summary.doc | awk '{print "Got " $1 ", Expected " 2888}'`
fi
if `test ! -s ./suplib.doc`
then
echo "writing ./suplib.doc"
cat > ./suplib.doc << '\Rogue\Monster\'
SUPLIB.DOC General C Support Library
COMPILATION
Compile all modules using a precompiled symbol table of all the
AMIGA include's (*/*.H) ... do *NOT* include standard aztec
includes (stdio.h, etc...). The Makefile for the precompiled symbol
table is in the LOCAL directory.
You must use the +L option (32 bit ints) for ALL COMPILATIONS, including
the generation of the symbol table when compiling SUPLIB (SUP32.LIB).
Also, use +B (no .begin reference), +CD (large code and data) model
when compiling this source.
MODULES
QINT: These are exception based prioritized software interrupt
routines. see QINT.DOC
ASYNCOP: Asynchronous function execution. Make asynchronous
function calls (not incredibly fast).
XFIO: Asyncronous file IO. Allows sequential asyncronous access
to files for both reading (reads ahead asyncronously) and
writing (writes asyncronously). Usually employed by CPU
bound programs not wishing to be slowed down even more by
the disk. Extremely useful for implementation of capture
and serial protocols.
DIO: Device IO package. This is a Generic interface for handling
the Amiga's EXEC devices. It makes your code smaller and
much easier to read. You no longer need to be a guru to
use devices.
BSTRING: memory move/set/compare routines. Operations are done in
longwords when possible.
SYS: System enhancement calls
MISC: misc. routines (break checking, openning/closing libraries),
date and time routines, setfiledate, etc...
---------------------------------------------------------------------
QINTS
SEE QINT.DOC
ASYNCH OP
handle= NewAsyncOp()
Create a new task for handling asynchronous function calls.
(void) StartAsyncOp(handle, func, arg1, arg2, arg3)
Queue up a function for the handle. Multiple functions may
be queueud. NOTE: The registers A4 and A5 will be initialized
to what they were when NewAsyncOp() was called.
The function must preserve D4-D7/A2-A3. D0-D3/A0-A1/A4-A6 may
be destroyed by the function.
bool = CheckAsyncOp(handle, n)
Return TRUE if a minimum of N async operations started with
StartAsyncOp() have completed, FALSE otherwise. The number
of async operations in progress is the number started minus
the number already waited for.
(void)= WaitAsyncOp(handle, n)
Wait for N of the operations in progress to complete. -1 can
be specified to wait for ALL the operations in progress to
complete.
For example, if you queue up 3 commands, CheckAsyncOp(handle, 3)
will check if all 3 have completed, and WaitAsyncOp(handle, 3)
waits and removes their reply messages as well as adjusts the
number of 'operations in progress' to 0.
I.E, if you were to WaitAsyncOp(handle, 2) instead of 3, after
it returns there will be 1 operation in progress left. If you
were to do another StartAsyncOp(), there would now by 2 in
progress.
(void) CloseAsyncOp(handle)
Wait for all operations in progress to end (WaitAsyncOp(handle,-1)),
then remove the task.
XFIO
xfi = xfopen(file, mode, bytes)
err = xfclose(xfi)
n = xfread(xfi, buf, n)
n = xfgets(xfi, buf, max)
err = xfwrite(xfi, buf, n)
mode is "r", "w", or "w+". No seeking is allowed as you can
see. If you openned for reading, you may NOT use xfwrite(),
and if you openned for writing, you may NOT use xfread().
r read
w write-newfile
w+ write-append
The specified buffer size (bytes) is used to create two
buffers of (bytes/2) bytes, double buffering either
asyncronous read ahead, or asyncronous writes.
'err' returns 1 if a write error occured. err is returned
by xfclose() (xfclose() waits for any asyncronous writes
to complete and thus can return whether they failed or not).
Once set, err stays set forever.
XFREAD: 0 is returned on EOF or error
XFGETS: the length of the string is returned. 0 is a valid
length (a blank line). -1 is returned on EOF or
error. The newline is removed and a string
terminator (0) added.
DIO
SEE DIO.DOC
BSTRING
(void) bmov(src,dest,bytes)
bool = bcmp(src,dest,bytes)
(void) bset(src, bytes, c)
(void) bzero(src, bytes)
These functions do various memory operations. bcmp() is does an
unsigned comparison, of course. bcmp() only checks for
equivalence, returning TRUE (1) if the buffers are the same,
FALSE (0) otherwise. bcmp() uses longword compares when possible.
bmov() does an ascending or decending copy as appropriate.
bmov(), bzero(), and bset() use longword and MULTIPLE REGISTER
operations when possible.
These functions are the same as the BSet(), BZero(), BMov(), and
BCmp() in my run-time library DRES.LIBRARY.
bool = checkbreak()
Check whether the process has received a ^C or ^D signal. ^D
is also checked here allowing a more reliable break-mechanism,
as Aztec and Lattice stdio routines will clear ^C even when
break is disabled.
(void) resetbreak()
(void) disablebreak()
(void) enablebreak()
resetbreak() clears both the ^C and ^D signals. disablebreak()
and enablebreak() modify the global variable Enable_Abort and
thus stdio's automatic break detection/abort.
bool = openlibs(flags)
bool = closelibs(flags)
See the flag definitions in XMISC.H. openlibs() opens all
specified libraries, returning 0 if one or more could not
be openned. closelibs() closes all specified libraries.
openlibs() does not open a library that is already open (if you
make the call more than once), and simply uses the already
open descriptor.
closelibs(-1) closes ALL libraries openned with openlibs(), but
NOT libraries openned otherwise.
Note that you cannot open or close DOS or EXEC. This is because
the C startup will do this for you, and also to prevent linker
warning messages.
Window= GetConWindow()
This functions retrieves the struct Window * from the console
device associated with this process. NULL is returned if the
window could not be found (still, operation may not be dependable
if the process's console is not a console device).
buf = datetos(date, buf, ctl)
DATESTAMP *date;
char *buf;
char *ctl;
This function converts a DOS DateStamp structure into a string
and places it in the specified buffer. ctl specifies the format
of the date by pieces (ctl can be NULL, indicating "D M Y h:m:s").
If not NULL, ctl is a string containing combinations of the
following characters. Spacing must also be specified. Any
unrecognized characters are passed to the output buffer verbatim.
D The day 23
M The month Jul
Y The year 1988
h The hour 03
m The minute 23
s The seconds 04
This function is equivalent to DateToS() in my run time library
DRES.LIBRARY
(void) llink(list, en) (OBSOLETE)
(void) lunlink(en) (OBSOLETE)
see XMISC.H . Simple doubly-linked list routines. XLIST is both
the list base and an element. The list base should be initialized
to zero before use.
(void) mountrequest(bool)
enable or disable the DOS requester which comes up when you attempt
to open a path not currently mounted. Normal mode is TRUE (1),
meaning that you get the requester. This routine remembers the
previous contents of pr_WindowPtr. The call mountrequest(0) may
be made multiple times and then mountrequest(1) will restore the
original contents of pr_WindowPtr.
RemSemaphore()
FindSemaphore() (SEE EXEC DOCUMENTATION FOR CALLING PARAMETERS)
AddSemaphore()
These functions fix the broken bindings in older Lattice and
Aztec libraries.
bool = setfiledate(file, date)
char *file;
DATESTAMP *date;
This function implements the new ACTION_SET_DATE packet and
sets the timestamp of a file. You cannot set the timestamp
for the root of a filesystem with this call.
This function is equivalent to the SetFileDate() function in
DRES.LIBRARY.
bool = wildcmp(wildstr, namestr)
compare the wildcard string (containing '*'s and '?'s) with
the file name (namestr) and return TRUE (1) if they compare,
and FALSE (0) otherwise.
This function is equivalent to the WildCmp() function in
DRES.LIBRARY.
(void) fhprintf(fh, ctrlstr, args...)
uses the EXEC formatted printing call to format text and then
writes it to an AMIGADOS file handle.
rval = AutoAllocMiscResource(resno, value)
resno: MR_SERIALPORT, SERIALBITS, PARALLELPORT, or PARALLELBITS
value: -1 to allocate, 0 to check.
This functions allocates or checks the specified resource. 0
(ZERO) is returned on SUCCESS (allocated or could allocate),
NON-ZERO is returned if the resource is already allocated by
somebody else.
(void)= AutoFreeMiscResource(resno)
Free's a resource you allocated. YOU MUST OWN THE RESOURCE!
Neither of these functions require you to open the misc.resource
resource.
font = GetFont(name, ysize)
This function searches both memory and the disk for the requested
font, and automatically opens/closes the diskfont library if it is
not already open. It opens the font, incrementing the reference
count.
(void) InitDeemuNW(ary, nw)
short *ary;
NW *nw;
ary points to the 'NW',' ' Deemu[] array entry. The NewWindow
structure is initialized according to the Deemu entry. Currently,
TopEdge, LeftEdge, Width, Height, DetailPen and BlockPen will
be initialized... less if the Deemu entry contains less information.
char *GetDEnv(name)
char *name;
Return a string to the enviroment variable name, returning NULL
if it does not exist.
bool SetDEnv(name, str)
char *name, *str;
Set the enviroment variable name to the string str. Return C-TRUE
(1) on success, or C-FALSE (0) on failure.
\Rogue\Monster\
else
echo "will not over write ./suplib.doc"
fi
if [ `wc -c ./suplib.doc | awk '{printf $1}'` -ne 9714 ]
then
echo `wc -c ./suplib.doc | awk '{print "Got " $1 ", Expected " 9714}'`
fi
echo "Finished archive 1 of 1"
# if you want to concatenate archives, remove anything after this line
exit
--
Bob Page, U of Lowell CS Dept. page@swan.ulowell.edu ulowell!page
Have five nice days.